#include "sphere.h"

#include <iostream>

Sphere::Sphere(Scene *scene) : Geometry(scene)
{
  std::cout << "Sphere Created" << std::endl;
}

Sphere::~Sphere()
{
}

void Sphere::loadAttributes(std::istream &inData)
{
  m_pos.loadAttributes(inData);
  inData >> m_radius;

  std::string materialName;
  inData >> materialName;

  m_material = Material::getMaterial(materialName);

  inData.ignore();
}

Collision Sphere::intersect(Ray r) const
{
  double a = r.dir.dot(),
         b = 2 * r.dir.x * (r.pos.x - m_pos.x) +
             2 * r.dir.y * (r.pos.y - m_pos.y) + 
             2 * r.dir.z * (r.pos.z - m_pos.z),
         c = m_pos.dot() + r.pos.dot() -
             2 * (r.pos.x * m_pos.x +
                  r.pos.y * m_pos.y +
                  r.pos.z * m_pos.z) -
             m_radius * m_radius;
  
  double discriminant = b * b - 4 * a * c;

  Collision result;
  result.isValid = false;

  if (discriminant <= 0)
  {
    return result;
  }
  
  double t = (-b - std::sqrt(discriminant)) / (2 * a);
  result.isValid = true;
  result.pos = r.pos + r.dir * t;
  result.normal = result.pos - m_pos;
  result.normal.normalize();
  result.distance = r.pos.distance(result.pos);
  result.parent = this;
  result.src = r.dir;
  result.material = m_material;
  result.recursionLevel = r.recursionLevel;
  result.ior = r.ior;

  if (result.normal.x != 0 || result.normal.z != 0)
  {
    result.u = std::atan2(result.normal.x, result.normal.z)/6.28;
  }
  else
  {
    result.u = 0;
  }
  result.v = std::asin(result.normal.y)/6.28;

  return result;
}
